package com.fast.utils.jwt;

import cn.hutool.json.JSONUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.InvalidClaimException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fast.enums.CodeEnum;
import com.fast.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.time.DateUtils;

import java.util.Date;

/**
 * @author ruan cai yuan
 * @version 1.0
 * @fileName com.fast.utils.jwt.JwtUtils
 * @description: JWT 的工具类
 * @since 2024/6/22 0:19
 */
@Slf4j
public class JwtUtils {
    private static final String SECRET = "LanYuanKeJiFastManager";

    /**
     * 生成 Token
     *
     * @param t   需要放到JWT里的数据部分
     * @param <T> 泛型
     * @return jwt 数据
     */
    public static <T> String getToken(T t) {
        Date expireDate = DateUtils.addMonths(new Date(), 1);
        JWTCreator.Builder builder = JWT.create().withClaim(t.getClass().getSimpleName(), JSONUtil.toJsonStr(t));
        return builder.withExpiresAt(expireDate).sign(Algorithm.HMAC256(SECRET));
    }

    /**
     * 验证token
     *
     * @param token token
     * @return DecodedJWT 对象
     */
    public static DecodedJWT verify(String token) {
        String errorMsg;
        try {
            return JWT.require(Algorithm.HMAC256(SECRET)).build().verify(token);
        } catch (AlgorithmMismatchException e) {
            errorMsg = "算法不匹配";
        } catch (InvalidClaimException e) {
            errorMsg = "声明无效";
        } catch (SignatureVerificationException e) {
            errorMsg = "签名不匹配";
        } catch (TokenExpiredException e) {
            errorMsg = "令牌失效";
        } catch (Exception e) {
            errorMsg = "校验令牌失效";
        }
        log.error("token verify failed , token : {} , reason : {}", token, errorMsg);
        throw new BusinessException(CodeEnum.UNAUTHORIZED);
    }

    /**
     * 解析 DecodedJWT 为指定的对象 clazz
     *
     * @param decodedJWT Jwt 中存储的载荷
     * @param clazz      指定对象
     * @param <T>        泛型
     * @return 解析出指定的对象
     */
    public static <T> T parse(DecodedJWT decodedJWT, Class<T> clazz) {
        Claim claim = decodedJWT.getClaim(clazz.getSimpleName());
        if (ObjectUtils.isEmpty(claim)) {
            return null;
        }
        return JSONUtil.toBean(claim.asString(), clazz);
    }
}
